package cn.xinfei.xdecision.httpclient;

import cn.xinfei.xdecision.common.utils.exception.ApiException;
import cn.xinfei.xdecision.common.utils.exception.enums.ErrorCodeEnum;
import cn.xinfei.xdecision.common.utils.util.SpringContextUtil;
import com.alibaba.fastjson.JSONObject;
import com.dianping.cat.Cat;
import io.micrometer.core.instrument.Metrics;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.client.*;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.web.client.AsyncRestTemplate;
import org.springframework.web.client.RestTemplate;

import java.util.Objects;

/**
 * RestTemplate配置
 */
@Configuration
@Slf4j
public class RestTemplateConfig {

    @Value("${spring.resttemplate.retry.backOffPeriod}")
    private static int backOffPeriod;

    @Value("${spring.resttemplate.retry.maxAttempts}")
    private static int maxAttempts;

    @Bean
    public AsyncRestTemplate asyncRestTemplate(@Qualifier("asyncClientHttpRequestFactory") AsyncClientHttpRequestFactory factory) {
        return new AsyncRestTemplate(factory);
    }

    @Value("${spring.resttemplate.factory.socketTimeout}")
    private int socketTimeout;

    @Value("${spring.resttemplate.factory.connectTimeout}")
    private int connectTimeout;

    @Bean
    public RestTemplate restTemplate(@Qualifier("simpleClientHttpRequestFactory") ClientHttpRequestFactory factory) {
        RestTemplate restTemplate = new RestTemplate();
        InterceptingClientHttpRequestFactory interceptorFactory = new InterceptingClientHttpRequestFactory(
                new BufferingClientHttpRequestFactory(factory), null);
        restTemplate.setRequestFactory(interceptorFactory);
        return restTemplate;
    }

    @Bean
    public ClientHttpRequestFactory simpleClientHttpRequestFactory(@Qualifier("poolingHttpClientConnectionManager") PoolingHttpClientConnectionManager manager) {
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
        factory.setHttpClient(HttpClientBuilder.create().setConnectionManager(manager).build());
        factory.setReadTimeout(socketTimeout);
        factory.setConnectTimeout(connectTimeout);
        return factory;
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.resttemplate.manager")
    public PoolingHttpClientConnectionManager poolingHttpClientConnectionManager() {
        return new PoolingHttpClientConnectionManager();
    }

    @Bean
    public AsyncClientHttpRequestFactory asyncClientHttpRequestFactory() {
        // 创建一个 httpCilent 简单工厂
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        // 设置连接超时
//        factory.setConnectTimeout(15000);
        // 设置读取超时
//        factory.setReadTimeout(5000);
        //设置异步任务（线程不会重用，每次调用时都会重新启动一个新的线程）
        factory.setTaskExecutor(new SimpleAsyncTaskExecutor());
        return factory;
    }

    public static void post(String reqUrl, String reqBody, ErrorCodeEnum errorCodeEnum) {
        try {
            RestTemplate restTemplate = SpringContextUtil.getBean(RestTemplate.class);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
            RetryTemplate retryTemplate = new RetryTemplate();

            SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
            retryPolicy.setMaxAttempts(4);//设置最大重试次数
            FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
            backOffPolicy.setBackOffPeriod(1000);//设置重试间隔时间
            retryTemplate.setRetryPolicy(retryPolicy);
            retryTemplate.setBackOffPolicy(backOffPolicy);

            JSONObject jo = retryTemplate.execute(context -> {
                //执行请求操作
                return restTemplate.postForObject(reqUrl, new HttpEntity<>(reqBody, headers), JSONObject.class);
            });
            log.info("reqUrl===>" + reqUrl + " ,responseBody===>" + jo);
            if (Objects.isNull(jo) || !"success".equals(jo.getString("result"))) {
                log.error("reqUrl===>{},responseBody===>{}", reqUrl, reqBody);
                throw new ApiException(errorCodeEnum);
            }
        } catch (Exception e) {
            log.error(errorCodeEnum.getMessage(), e);
            Cat.logError(e); // 将异常上报到cat上
            Metrics.counter("xengine_action_total", "action", "list-server").increment();
            throw new ApiException(errorCodeEnum);
        }
    }
}
